package com.mall.b2c.util;

import java.util.Date;

import org.apache.commons.lang3.StringUtils;

import redis.clients.jedis.Jedis;

import com.mall.common.hibernate.Finder;
import com.mall.common.util.DateHelper;
import com.mall.common.util.PropertiesHelper;

/**
 * 工具类 - 编号生成
 */
public class SerialNumberUtil {

	public static final String ORDER_SN_PREFIX = "";// 订单编号前缀
	public static final long ORDER_SN_FIRST = 100000L;// 订单编号起始数
	public static final long ORDER_SN_STEP = 1L;// 订单编号步长
	public static final String RECHARGE_SN_PREFIX = "R2D";// 余额充值流水号前缀
	public static final long RECHARGE_SN_FIRST = 10000L;// 余额充值流水号起始数
	public static final long RECHARGE_SN_STEP = 1L;// 余额充值流水号步长
	public static final String TRADE_SN_PREFIX = "CT";// 支付编号前缀
	public static final long TRADE_SN_FIRST = 10000L;// 支付编号起始数
	public static final long TRADE_SN_STEP = 1L;// 支付编号步长
	public static final String PD_SN_PREFIX = "PD";//收支明细流水号前缀
	public static final long PD_SN_FIRST = 10000L;// 收支明细流水号起始数
	public static final long PD_SN_STEP = 1L;//收支明细流水号步长
	public static final String SP_SN_PREFIX = "SP";//发货单号前缀
	public static final long SP_SN_FIRST = 10000L;// 发货单号起始数
	public static final long SP_SN_STEP = 1L;//发货单号步长
	public static final String RN_SN_PREFIX = "RN";//退款单号前缀

	public static final String CD_SN_PREFIX = "CD";//卡号前缀
	public static final long CD_SN_STEP = 1L;//发货单号步长

	public static final long RN_SN_FIRST = 10000L;// 退款单号起始数
	public static final long RN_SN_STEP = 1L;//退款单号步长
	public static Long lastOrderSnNumber;
	public static Long lastRechargeNumber;
	public static Long lastTradeNumber;
	public static Long lastPaymentNumber;
	public static Long lastShippingNumber;
	public static Long lastRefundNumber;
	private static Jedis jedis;
	
	static{
		String ip = PropertiesHelper.getPropertiesValue("config", "redis.ip");
		String port = PropertiesHelper.getPropertiesValue("config", "redis.port");
		String password = PropertiesHelper.getPropertiesValue("config", "redis.password");
		String database = PropertiesHelper.getPropertiesValue("config", "redis.database");
		if(StringUtils.isNotBlank(ip)
				&& StringUtils.isNotBlank(port)){
			try {
				jedis = new Jedis(ip, Integer.parseInt(port), 30000);
				if (StringUtils.isNotBlank(password)) {
					jedis.auth(password);
				}
				if (StringUtils.isNotBlank(database)) {
					int db = Integer.parseInt(database);
					if (db != 0) {
						jedis.select(db);
					}
				}
			} catch (Exception e) {
				jedis = null;
			}
		}else{
			jedis = null;
		}
		Finder finder = Finder.create("select max(bean.orderNo) from OrderDomain bean where length(bean.orderNo) >= 20");
		Object obj = finder.findUniqueByHQL();
		if(obj == null){
			lastOrderSnNumber = ORDER_SN_FIRST;
		}else{
			lastOrderSnNumber = Long.parseLong(StringUtils.removeStartIgnoreCase(obj.toString(), ORDER_SN_PREFIX).substring(14));
		}
		
		finder = Finder.create("select max(bean.tradeNo) from PaymentDetailDomain bean where bean.tradeNo like '" + RECHARGE_SN_PREFIX + "%'");
		obj = finder.findUniqueByHQL();
		if(obj == null){
			lastRechargeNumber = RECHARGE_SN_FIRST;
		}else{
			lastRechargeNumber = Long.parseLong(StringUtils.removeStartIgnoreCase(obj.toString(), RECHARGE_SN_PREFIX).substring(14));
		}
		
		finder = Finder.create("select max(bean.tradeNo) from OrderDomain bean");
		obj = finder.findUniqueByHQL();
		if(obj == null){
			lastTradeNumber = TRADE_SN_FIRST;
		}else{
			lastTradeNumber = Long.parseLong(StringUtils.removeStartIgnoreCase(obj.toString(), TRADE_SN_PREFIX).substring(14));
		}
		
		finder = Finder.create("select max(p.paymentNo) from PaymentDetailDomain p");
		obj = finder.findUniqueByHQL();
		if(obj == null){
			lastPaymentNumber = PD_SN_FIRST;
		}else{
			lastPaymentNumber = Long.valueOf(StringUtils.removeStartIgnoreCase(obj.toString(), PD_SN_PREFIX).substring(8));
		}
		
		finder = Finder.create("select max(s.sendSn) from ShippingDomain s");
		obj = finder.findUniqueByHQL();
		if(obj == null){
			lastShippingNumber = SP_SN_FIRST;
		}else{
			lastShippingNumber = Long.valueOf(StringUtils.removeStartIgnoreCase(obj.toString(), SP_SN_PREFIX).substring(14));
		}
		
		finder = Finder.create("select max(s.refundNo) from RefundDomain s");
		obj = finder.findUniqueByHQL();
		if(obj == null){
			lastRefundNumber = RN_SN_FIRST;
		}else{
			lastRefundNumber = Long.valueOf(StringUtils.removeStartIgnoreCase(obj.toString(), RN_SN_PREFIX).substring(14));
		}
	}
	
	/**
	 * 生成订单编号
	 * @return
	 */
	public synchronized static String buildOrderNo(){
		lastOrderSnNumber = getLastSerialNumber("orderNo", lastOrderSnNumber, ORDER_SN_STEP);
		return ORDER_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMddHHmmss") + String.format("%06d", lastOrderSnNumber);
	}
	
	/**
	 * 生成充值编号
	 * @return
	 */
	public synchronized static String buildRechargeNo(){
		lastRechargeNumber = getLastSerialNumber(RECHARGE_SN_PREFIX, lastRechargeNumber, RECHARGE_SN_STEP);
		return RECHARGE_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMddHHmmss") + String.format("%05d", lastRechargeNumber);
	}
	
	/**
	 * 生成付款编号
	 * @return
	 */
	public synchronized static String buildTradeNo(){
		lastTradeNumber = getLastSerialNumber(TRADE_SN_PREFIX, lastTradeNumber, TRADE_SN_STEP);
		return TRADE_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMddHHmmss") + String.format("%05d", lastTradeNumber);
	}

	/**
	 * 收支明细编号
	 * @return
	 */
	public synchronized static String buildPaymentSn() {
		lastPaymentNumber = getLastSerialNumber(PD_SN_PREFIX, lastPaymentNumber, PD_SN_STEP);
		return PD_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMdd") + String.format("%05d", lastPaymentNumber);
	}
	
	/**
	 * 生成发货单编号
	 * @return
	 */
	public synchronized static String buildShippingSn(){
		lastShippingNumber = getLastSerialNumber(SP_SN_PREFIX, lastShippingNumber, SP_SN_STEP);
		return SP_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMddHHmmss") + String.format("%05d", lastShippingNumber);
	}
	
	/**
	 * 生成发货单编号
	 * @return
	 */
	public synchronized static String buildRefundSn(){
		lastRefundNumber = getLastSerialNumber(RN_SN_PREFIX, lastShippingNumber, RN_SN_STEP);
		return RN_SN_PREFIX + DateHelper.date2String(new Date(), "yyyyMMddHHmmss") + String.format("%05d", lastRefundNumber);
	}


	private static long getLastSerialNumber(String key, long lastNum, long step){
		if(jedis == null){
			lastNum += step;
		}else{
			try {
				lastNum = jedis.incr(key);
			} catch (Exception e) {
				lastNum += step;
			}
		}
		return lastNum;
	}
}